
#include "cs_t2cmanager.h"
#include <QStringList>
#include <QVariant>
#include <QDateTime>
#include "ProcessVariable.h"
#include "QueryMicroMan.h"


//-------------------------------------

T2CManager::T2CManager(QObject *parent) :
    QObject( parent ),
    thread( new QThread() ),
    qmm( new QueryMicroMan() )
{
    connect( this, SIGNAL(sgnConnect(QString,quint16)), qmm, SLOT(Connect(QString,quint16)));
    connect( this, SIGNAL(sgnDisconnect()), qmm, SLOT(Disconnect()));
    connect( this, SIGNAL(sgnExecCmd(QString)), qmm, SLOT(ExecCmd(QString)));
    //connect( qmm, SIGNAL(updated(QString)), this, SLOT(sltQueryUpdated(QString)) );
    connect( qmm, SIGNAL( sgnSendResponse(QString) ), this, SLOT( sltReceiveResponseList(QString) ) );
    connect( qmm, SIGNAL( sgnConnected() ), this, SLOT( sltSockConnected() ) );
    connect( qmm, SIGNAL( sgnDisconnected() ), this, SIGNAL( sgnDisconnected() ) );


    qmm->moveToThread( thread );
    thread->start();
}

//-------------------------------------

void T2CManager::ExecCmd( QString cmd )
{
    emit sgnExecCmd( cmd );
}

//-------------------------------------

void T2CManager::Connect( QString h, quint16 p )
{
    emit sgnConnect( h, p );
}

//-------------------------------------

void T2CManager::Disconnect()
{
    emit sgnDisconnect();
}

//-------------------------------------

ProcessVariable * T2CManager::getVariable( quint64 idf, quint64 timeout )
{
    emit sgnExecCmd( QString( "ANM 0 ORG %1" ).arg( idf ) );

    ProcessVariable * pv = 0;

    if( checkTimeout( timeout ) )
    {
        pv = parseAnswer( qmm->outStr );
        if( pv )
        {
            PVs.insert( idf, pv );
            emit valueUpdated( pv->idf );
        }
    }
    return pv;
}

//-------------------------------------

bool T2CManager::waitForReady( quint64 timeout )
{
    emit sgnExecCmd( "T2C CPL" );

    ProcessVariable * pv = new ProcessVariable();
    //pv.init();

    if( checkTimeout( timeout ) )
    {
        pv = parseAnswer( qmm->outStr );
        if( pv->cmd == NO_CMD_STR )
        {
            verInfo = pv->value.toString();
            return true;
        }
    }
    return false;
}

//-------------------------------------

void T2CManager::wait( quint64 & to )
{
    QTime t1;
    t1.start();
    QTime t2 = t1.addMSecs( to );
    while( t1 < t2 )
         t1.start();
}

//-------------------------------------

bool T2CManager::checkTimeout( quint64 & to )
{
    quint64 halfTO = to;
    halfTO /= 2;
    int cnt = 0;
    wait( halfTO );
    while( qmm->locked )
    {
        if( qmm->locked )
        {
            wait( halfTO );
            cnt++;
        }
        else
            break;
    }

    if( cnt <= 1 )
        return true;

    return false;
}

//-------------------------------------

ProcessVariable * T2CManager::parseAnswer( QString & s )
{

    ProcessVariable * pv = 0;

    if( s == TIMEOUTED_STR )
        return pv;

    QStringList tmp_sl = s.split(" ");

    if( s.contains( "Test-Version" ) )
    {
        pv->value = QVariant( s );
        pv->svalue = s;
        pv->cmd = NO_CMD_STR;
    }

    if( tmp_sl.count() >= 7 && tmp_sl[0] == "DAT" )
    {
        pv = new ProcessVariable();
        pv->idf = tmp_sl[2].toULongLong();
        pv->type = tmp_sl[3];
        pv->value = QVariant( tmp_sl[ tmp_sl.count()-3 ] );
        pv->svalue = tmp_sl[ tmp_sl.count()-3 ];
        pv->time.setMSecsSinceEpoch( (qint64)( tmp_sl[6].toDouble()*1000 ) );
        pv->cmd.clear();
        for( int j=0; j < tmp_sl.count()-2; j++ )
            pv->cmd += ( tmp_sl[j] + ( j == tmp_sl.count()-3 ? "" : " " ) );

        QString status = tmp_sl[5];
        char symb;

        pv->s = ProcessVariable::OK;
        for( int i = 0; i < status.length(); i++ )
        {
            symb = status.at( i ).toAscii();

            switch( symb )
            {
                case 'N':
                    pv->s |= ProcessVariable::NotOK;
                    break;
                case 'T':
                    pv->s |= ProcessVariable::Test;
                    break;
                case 'G':
                    pv->s |= ProcessVariable::Blocked;
                    break;
                case 'B':
                    pv->s |= ProcessVariable::UserEntry;
                    break;
                case 'E':
                    pv->s |= ProcessVariable::Substituted;
                    break;
                case 'A':
                    pv->s |= ProcessVariable::Queried;
                    break;
                case 'R':
                    pv->s |= ProcessVariable::Reserved;
                    break;
            }
        }
    }
    return pv;
}

//-------------------------------------
/*
ProcessVariable * T2CManager::sltQueryUpdated( QString s )
{
    return parseAnswer( s );
}
*/
//-------------------------------------

ProcessVariable * T2CManager::probeVariable( quint64 idf, quint64 timeout )
{
    emit sgnExecCmd( QString( "ANM 0 TST %1" ).arg( idf ) );

    ProcessVariable * pv = new ProcessVariable();
    //pv.init();
    if( checkTimeout( timeout ) )
    {
        pv = parseAnswer( qmm->outStr );
    }
    //int cp=1;
    return pv;
}

//-------------------------------------

void T2CManager::subscribe( quint64 idf, bool inquiry )
{
    if( inquiry )
        emit sgnExecCmd( QString( "ANM 0 ORG %1" ).arg( idf ) );
    else
        emit sgnExecCmd( QString( "ANM 0 DYN %1" ).arg( idf ) );
}

//-------------------------------------

void T2CManager::unsubscribe( quint64 idf )
{
    emit sgnExecCmd( QString( "ANM 0 END %1" ).arg( idf ) );
}

//-------------------------------------

void T2CManager::waitForValueChange( quint64 idf, quint64 waitTime )
{
    if( PVs.contains( idf ) )
    {
        wait( waitTime );
    }
}

//-------------------------------------

void T2CManager::sltReceiveResponseList( QString txt )
{
    QStringList sl = txt.split( "\n" );
    sl.removeAll( "" );
    sl.removeAll( " " );
    QString s;
    for( int i=0; i < sl.count(); ++i )
    {
        s = sl.at( i );
        parseAnswer( s );
    }
    emit sgnSendToLog( txt );
}

//-------------------------------------

void T2CManager::sltSockConnected()
{
    emit sgnConnected();
}

//-------------------------------------

bool T2CManager::isConnected()
{
    return qmm->isConnected();
}

//-------------------------------------

ProcessVariable * T2CManager::GetVarFromStorage( quint64 idf )
{
    if( PVs.contains( idf ) )
        return PVs[ idf ];
    else
        return getVariable( idf );
}

//-------------------------------------
